package algostruct

import (
	"iter"
	"sync"
)

type Set[T comparable] interface {
	//添加元素到集合
	Add(item T) bool
	// 从集合中移除元素
	Remove(item T) bool
	//检查集合是否包含元素
	Contains(item T) bool
	//返回集合大小
	Size() int
	//清空集合
	Clear()
	//返回集合中所有元素的切片
	Items() []T
	//迭代器 (Go 1.23+)
	Iter() iter.Seq[T]
}

type safeSet[T comparable] struct {
	items map[T]struct{}
	mu    sync.RWMutex
}

// 创建一个新的线程安全的泛型 Set
func NewSet[T comparable]() Set[T] {
	return &safeSet[T]{
		items: make(map[T]struct{}),
	}
}

// Add 向安全集合中添加一个元素。
// 该方法使用了互斥锁来确保并发安全。
// 参数:
//
//	item - 要添加到集合中的元素。
//
// 返回值:
//
//	bool - 如果元素被成功添加，则返回true；如果元素已存在，则返回false。
func (s *safeSet[T]) Add(item T) bool {
	// 加锁以保护集合的并发访问
	s.mu.Lock()
	defer s.mu.Unlock()

	// 检查元素是否已经存在于集合中
	if _, exists := s.items[item]; exists {
		// 如果元素已存在，返回false
		return false
	}
	// 将元素添加到集合中
	s.items[item] = struct{}{}
	// 元素添加成功，返回true
	return true
}

// Remove 从 safeSet 中安全地移除一个元素。
// 该函数首先使用互斥锁确保并发安全，然后检查元素是否存在于映射中。
// 如果元素存在，则从映射中删除它，并返回 true 表示删除成功。
// 如果元素不存在，则不进行删除操作，并返回 false。
func (s *safeSet[T]) Remove(item T) bool {
	// 加锁以确保并发安全。
	s.mu.Lock()
	defer s.mu.Unlock()

	// 检查元素是否存在于映射中。
	if _, exists := s.items[item]; !exists {
		return false
	}

	// 从映射中删除元素。
	delete(s.items, item)
	return true
}

// Contains 检查一个项是否存在于 safeSet 中。
// 它使用读锁来防止数据竞争，确保并发安全。
// 参数:
//
//	item T: 要检查的项。
//
// 返回值:
//
//	bool: 如果项存在于集合中，则返回 true，否则返回 false。
func (s *safeSet[T]) Contains(item T) bool {
	// 使用读锁来防止数据竞争，确保并发安全。
	s.mu.RLock()
	defer s.mu.RUnlock()

	// 检查项是否存在于映射中。
	_, exists := s.items[item]
	return exists
}

// Size 返回安全集合中元素的数量。
// 该方法使用读锁来防止数据在执行期间被修改，确保返回的大小是准确的。
// 读锁在方法结束后自动释放，以减少锁的持有时间。
func (s *safeSet[T]) Size() int {
	s.mu.RLock()
	defer s.mu.RUnlock()

	return len(s.items)
}

// Clear 清空safeSet中的所有元素。
// 该函数通过加锁确保在同一时间内只有一个协程能够修改safeSet，
// 防止并发访问导致的数据竞争问题。
func (s *safeSet[T]) Clear() {
	// 加锁，确保线程安全。
	s.mu.Lock()
	defer s.mu.Unlock()

	// 创建一个新的空map来存储items，清空原有map中的所有数据。
	s.items = make(map[T]struct{})
}

// Items 返回安全集中的所有元素副本。
// 此方法确保在返回时持有读锁，以防止在复制元素期间对集合进行修改。
// 返回值是集合中元素的切片，元素类型为 T。
func (s *safeSet[T]) Items() []T {
	// 上读锁以防止数据竞争，确保线程安全。
	s.mu.RLock()
	defer s.mu.RUnlock()

	// 初始化一个切片用于存放集合中的所有元素，预设容量为集合元素的数量以提高性能。
	items := make([]T, 0, len(s.items))
	// 遍历集合中的每个元素，并将其添加到切片中。
	for item := range s.items {
		items = append(items, item)
	}
	// 返回包含集合中所有元素的切片。
	return items
}

// Iter 实现了 iter.Seq[T] 接口，用于安全地迭代集合中的元素。
// 它接受一个 yield 函数作为参数，该函数用于处理每个元素。
// 如果 yield 函数返回 false，迭代将提前终止。
// 该方法确保了在迭代过程中对集合的读取是线程安全的。
func (s *safeSet[T]) Iter() iter.Seq[T] {
	return func(yield func(T) bool) {
		// 在迭代之前获取读锁，以确保线程安全。
		s.mu.RLock()
		defer s.mu.RUnlock()

		// 遍历集合中的每个元素，并使用 yield 函数进行处理。
		// 如果 yield 返回 false，提前退出迭代。
		for item := range s.items {
			if !yield(item) {
				return
			}
		}
	}
}
